package com.optitronics.beans;

import java.math.BigDecimal;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import javax.persistence.TypedQuery;
import javax.persistence.Version;

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.transaction.annotation.Transactional;

import com.optitronics.util.OptitronicsConstants;
import com.optitronics.util.OptitronicsUtils;

@Configurable
@Entity
@Table(name = "products")
public class Product {

	public static final Integer PURPOSE_COMPANIES = Integer.valueOf(0);
	public static final Integer PURPOSE_PERSONS = Integer.valueOf(1);

	@PersistenceContext
	transient EntityManager entityManager;

	@Id
	@TableGenerator(name = "productsGenerator", pkColumnValue = "PRODUCTS", table = OptitronicsConstants.COUNTER_TABLE_NAME, pkColumnName = OptitronicsConstants.COUNTER_PK_COLUMN_NAME, valueColumnName = OptitronicsConstants.COUNTER_VALUE_COLUMN_NAME, allocationSize = OptitronicsConstants.COUNTER_ALLOCATION_SIZE)
	@GeneratedValue(strategy = GenerationType.TABLE, generator = "productsGenerator")
	@Column(name = "ID")
	private Integer id;

	@Version
	@Column(name = "VERSION")
	private Integer version;

	@Column(name = "NAME")
	private String name;

	@Column(name = "TAX_INCLUDED_IN_PRICE")
	private Boolean taxIncludedInPrice;

	@Column(name = "PURPOSE")
	private Integer purpose;

	@Column(name = "ACTIVE")
	private Boolean active;

	@Column(name = "PRICE_NEW")
	private BigDecimal priceNew;

	@Column(name = "PRICE_RENEVAL")
	private BigDecimal priceReneval;

	@Column(name = "PRICE_ACADEMIC")
	private BigDecimal priceAcademic;

	@Column(name = "PRICE_STUDENT")
	private BigDecimal priceStudent;

	@Column(name = "PRICE_PENSIONER")
	private BigDecimal pricePensioner;

	@Column(name = "PRICE_GRAPHIC_DESIGNER")
	private BigDecimal priceGraphicDesigner;

	@Column(name = "PRICE_NUNS")
	private BigDecimal priceNuns;

	@Column(name = "DISCOUNT")
	private BigDecimal discount;

	@Column(name = "DESCRIPTION")
	private String description;

	public Product() {
		super();
	}

	public Integer getVersion() {
		return this.version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Boolean getTaxIncludedInPrice() {
		return this.taxIncludedInPrice;
	}

	public void setTaxIncludedInPrice(Boolean taxIncludedInPrice) {
		this.taxIncludedInPrice = taxIncludedInPrice;
	}

	public BigDecimal getPriceNew() {
		return this.priceNew;
	}

	public void setPriceNew(BigDecimal priceNew) {
		this.priceNew = priceNew;
	}

	public BigDecimal getPriceReneval() {
		return this.priceReneval;
	}

	public void setPriceReneval(BigDecimal priceReneval) {
		this.priceReneval = priceReneval;
	}

	public BigDecimal getPriceStudent() {
		return this.priceStudent;
	}

	public void setPriceStudent(BigDecimal priceStudent) {
		this.priceStudent = priceStudent;
	}

	public BigDecimal getPricePensioner() {
		return this.pricePensioner;
	}

	public void setPricePensioner(BigDecimal pricePensioner) {
		this.pricePensioner = pricePensioner;
	}

	public BigDecimal getPriceGraphicDesigner() {
		return this.priceGraphicDesigner;
	}

	public void setPriceGraphicDesigner(BigDecimal priceGraphicDesigner) {
		this.priceGraphicDesigner = priceGraphicDesigner;
	}

	public BigDecimal getPriceNuns() {
		return this.priceNuns;
	}

	public void setPriceNuns(BigDecimal priceNuns) {
		this.priceNuns = priceNuns;
	}

	public Integer getId() {
		return this.id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Transactional
	public void persist() {
		if (this.entityManager == null)
			this.entityManager = entityManager();
		this.entityManager.persist(this);
	}

	@Transactional
	public void flush() {
		if (this.entityManager == null)
			this.entityManager = entityManager();
		this.entityManager.flush();
	}

	@Transactional
	public Product merge() {
		if (this.entityManager == null)
			this.entityManager = entityManager();
		Product merged = this.entityManager.merge(this);
		this.entityManager.flush();
		return merged;
	}

	public static final EntityManager entityManager() {
		EntityManager em = new Product().entityManager;
		if (em == null)
			throw new IllegalStateException(
					"Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
		return em;
	}

	public static final Integer ORDER_TYPE_NEW = Integer.valueOf(0);
	public static final Integer ORDER_TYPE_RENEWAL = Integer.valueOf(1);
	public static final Integer ORDER_TYPE_ACADEMIC = Integer.valueOf(2);
	public static final Integer ORDER_TYPE_STUDENT = Integer.valueOf(3);
	public static final Integer ORDER_TYPE_PENSIONER = Integer.valueOf(4);
	public static final Integer ORDER_TYPE_NUNS = Integer.valueOf(5);
	public static final Integer ORDER_GRAPHIC_DESIGNER = Integer.valueOf(6);

	public static Integer[] getOrderTypes(Product product) {

		Integer[] orderTypes = {};
		if (PURPOSE_COMPANIES.equals(product.getPurpose())) {
			orderTypes = new Integer[] { OptitronicsConstants.ORDER_TYPE_NEW, OptitronicsConstants.ORDER_TYPE_RENEWAL,
					OptitronicsConstants.ORDER_TYPE_ACADEMIC };
		} else {
			orderTypes = new Integer[] { OptitronicsConstants.ORDER_TYPE_NEW, OptitronicsConstants.ORDER_TYPE_RENEWAL,
					OptitronicsConstants.ORDER_TYPE_STUDENT, OptitronicsConstants.ORDER_TYPE_PENSIONER,
					OptitronicsConstants.ORDER_TYPE_NUNS, OptitronicsConstants.ORDER_GRAPHIC_DESIGNER };
		}

		return orderTypes;
	}

	public static List<Product> findProducts(Integer purpose, int firstResult, int maxResults) {

		String queryString = "SELECT p FROM Product p WHERE p.purpose = :purpose ";
		if (OptitronicsUtils.isUserReseller()) {
			queryString += " AND p.active = :active ";
		}
		queryString += " ORDER by p.name ";

		TypedQuery<Product> query = entityManager().createQuery(queryString, Product.class);
		query.setParameter("purpose", purpose);
		if (OptitronicsUtils.isUserReseller()) {
			query.setParameter("active", Boolean.TRUE);
		}

		if (firstResult != -1 && maxResults != -1) {
			query.setFirstResult(firstResult);
			query.setMaxResults(maxResults);
		}

		return query.getResultList();
	}

	public static int countProducts(Integer purpose) {

		String queryString = "SELECT COUNT(*) FROM Product p WHERE p.purpose = :purpose ";
		if (OptitronicsUtils.isUserReseller()) {
			queryString += " AND p.active = :active ";
		}

		Query query = entityManager().createQuery(queryString);
		query.setParameter("purpose", purpose);
		if (OptitronicsUtils.isUserReseller()) {
			query.setParameter("active", Boolean.TRUE);
		}

		return ((Number) query.getSingleResult()).intValue();
	}

	public static Product findProduct(Integer id) {
		if (id == null)
			return null;
		return entityManager().find(Product.class, id);
	}

	public static List<Product> findProductEntries(int firstResult, int maxResults) {
		return entityManager().createQuery("select o from Product o", Product.class).setFirstResult(firstResult)
				.setMaxResults(maxResults).getResultList();
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("Version: ").append(getVersion()).append(", ");
		sb.append("Name: ").append(getName()).append(", ");
		sb.append("TaxIncludedInPrice: ").append(getTaxIncludedInPrice()).append(", ");
		sb.append("Purpose: ").append(getPurpose()).append(", ");
		sb.append("PriceNew: ").append(getPriceNew()).append(", ");
		sb.append("PriceReneval: ").append(getPriceReneval()).append(", ");
		sb.append("PriceStudent: ").append(getPriceStudent()).append(", ");
		sb.append("PricePensioner: ").append(getPricePensioner()).append(", ");
		sb.append("priceAcademic: ").append(getPriceAcademic()).append(", ");
		sb.append("PriceGraphicDesigner: ").append(getPriceGraphicDesigner()).append(", ");
		sb.append("PriceNuns: ").append(getPriceNuns()).append(", ");
		sb.append("Id: ").append(getId());
		return sb.toString();
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Boolean getActive() {
		return active;
	}

	public void setActive(Boolean active) {
		this.active = active;
	}

	public Integer getPurpose() {
		return purpose;
	}

	public void setPurpose(Integer purpose) {
		this.purpose = purpose;
	}

	public BigDecimal getPriceAcademic() {
		return priceAcademic;
	}

	public void setPriceAcademic(BigDecimal priceAcademic) {
		this.priceAcademic = priceAcademic;
	}

	public BigDecimal getDiscount() {
		return discount;
	}

	public void setDiscount(BigDecimal discount) {
		this.discount = discount;
	}
}
